/**
 * Copyright (C) 2010 Daniel <daniel.petisme@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * 
 */
package fr.daniel.todolist.test.model.services.util;

import java.sql.SQLException;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.dbunit.DatabaseUnitException;
import org.dbunit.JdbcBasedDBTestCase;
import org.dbunit.database.AmbiguousTableNameException;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.DefaultDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.operation.DatabaseOperation;
import org.eclipse.persistence.exceptions.DatabaseException;

/**
 * @author Daniel
 * 
 */
public class DataTestManager extends JdbcBasedDBTestCase {

	private static Logger log = Logger.getLogger(DataTestManager.class);

	// MLD Definition
	public static final String PRIORITY_TABLE = "PRIORITY";
	public static final String TODO_TABLE = "TODO";

	public static final int NB_ROWS_PRIORITY_DATA_SET = 5;
	public static final int NB_ROWS_TODO_DATA_SET = 5;

	// Persitence
	private static final String PERSISTENCE_UNIT_NAME = "todolist";

	@PersistenceUnit(name = "todolist")
	private EntityManagerFactory factory;
	@PersistenceContext
	private EntityManager em;

	// Singleton
	private static DataTestManager instance;

	/**
	 * Default singleton constructor
	 */
	private DataTestManager() {
		factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
		em = factory.createEntityManager();		
	}

	/**
	 * @return The unique instance
	 */
	public static DataTestManager getDataTestManager() {
		if (instance == null) {
			instance = new DataTestManager();
		}
		return instance;
	}

	/**
	 * Load a data set
	 * 
	 * @param path
	 *            The path of the XML DataSet
	 * @return the data set
	 */
	private IDataSet loadXMLDataSet(String path) {
		IDataSet exampleDataSet = null;
		try {
			exampleDataSet = new FlatXmlDataSetBuilder().build(getClass()
					.getResource(path));
		} catch (DataSetException e) {
			log.debug(e.getMessage());
		}

		return exampleDataSet;
	}

	/**
	 * Load XML data to fill the priority data table
	 * 
	 * @param path
	 *            the path of the XML file
	 */
	public void loadPriorities(String path) {
		IDataSet exampleDataSet = loadXMLDataSet(path);
		if (exampleDataSet != null) {
			ITable prioritiesToInsert = null;

			try {
				prioritiesToInsert = exampleDataSet.getTable(PRIORITY_TABLE);

			} catch (DataSetException e) {
				log.debug(e.getMessage());
			}
			try {
				DatabaseOperation.CLEAN_INSERT.execute(getConnection(),
						new DefaultDataSet(prioritiesToInsert));
			} catch (DatabaseException e) {
				log.debug(e.getMessage());
			} catch (AmbiguousTableNameException e) {
				log.debug(e.getMessage());
			} catch (DatabaseUnitException e) {
				log.debug(e.getMessage());
			} catch (SQLException e) {
				log.debug(e.getMessage());
			} catch (Exception e) {
				log.debug(e.getMessage());
			}

			Query q = em.createQuery("select p from Priority p");
			assertNotNull(q.getResultList());
			assertEquals(NB_ROWS_PRIORITY_DATA_SET, q.getResultList().size());

			// Garbage
			q = null;
		}

		// Garbage
		exampleDataSet = null;
	}

	/**
	 * Load XML data to fill the todo data table
	 * 
	 * @param path
	 *            the path of the XML file
	 */
	public void loadTodos(String path) {

		IDataSet exampleDataSet = loadXMLDataSet(path);
		if (exampleDataSet != null) {
			ITable todosToInsert = null;

			try {
				todosToInsert = exampleDataSet.getTable(TODO_TABLE);

			} catch (DataSetException e) {
				log.debug(e.getMessage());
			}
			try {
				DatabaseOperation.CLEAN_INSERT.execute(getConnection(),
						new DefaultDataSet(todosToInsert));
			} catch (DatabaseException e) {
				log.debug(e.getMessage());
			} catch (AmbiguousTableNameException e) {
				log.debug(e.getMessage());
			} catch (DatabaseUnitException e) {
				log.debug(e.getMessage());
			} catch (SQLException e) {
				log.debug(e.getMessage());
			} catch (Exception e) {
				log.debug(e.getMessage());
			}

			// Check
			Query q = em.createQuery("select t from Todo t");
			assertNotNull(q.getResultList());
			assertEquals(NB_ROWS_TODO_DATA_SET, q.getResultList().size());

			// Garbage
			q = null;
		}

		// Garbage
		exampleDataSet = null;

	}

	/**
	 * Clear saved todos rows
	 */
	public void clearTodos() {

		if (!em.getTransaction().isActive()) {
			em.getTransaction().begin();
		}

		em.createQuery("delete from Todo").executeUpdate();

		em.getTransaction().commit();

		// Check
		Query q = em.createQuery("select t from Todo t");
		assertNotNull(q.getResultList());
		assertEquals(0, q.getResultList().size());

		// Garbage
		q = null;
	}

	/**
	 * Clear saved priorities rows
	 */
	public void clearPriorities() {

		if (!em.getTransaction().isActive()) {
			em.getTransaction().begin();
		}

		em.createQuery("delete from Priority").executeUpdate();

		em.getTransaction().commit();

		// Check
		Query q = em.createQuery("select p from Priority p");
		assertNotNull(q.getResultList());
		assertEquals(0, q.getResultList().size());

		// Garbage
		q = null;
	}

	/**
	 * Destroy access to the database
	 */
	public void destroy() {

		if (em != null) {
			em.close();
		}
		if (factory != null) {
			factory.close();
		}

		// Garbage
		instance = null;
		em = null;
		factory = null;

	}

	@Override
	protected String getConnectionUrl() {
		return (String) em.getProperties().get("javax.persistence.jdbc.url");
	}

	@Override
	protected String getDriverClass() {
		return (String) em.getProperties().get("javax.persistence.jdbc.driver");
	}

	@Override
	protected IDataSet getDataSet() throws Exception {
		return getConnection().createDataSet();
	}

}
